home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Almathera Ten Pack 3: CDPD 3
/
Almathera Ten on Ten - Disc 3: CDPD3.iso
/
ab20
/
unarced
/
utilities
/
misc
/
shelltimer
/
shelltimerdaemon.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-03-17
|
9KB
|
456 lines
;/* Execute me to Compile and link ShellTimerDaemon.c
shelltimer start verbose
; For debugging, use the following command:
; lc -. -O -ms -b1 -cfistq -j73 -v -Lit -d3 -isrc:memlib -dMWDEBUG=1 ShellTimerDaemon.c
; For production, use the following command:
lc -. -O -ms -b1 -cfistq -j73 -Lit ShellTimerDaemon.c
echo "Time to compile and link: " NOLINE
shelltimer stop
quit
*/
/***
**** SHELLTIMERDAEMON.C
****
**** Creation: John Lindwall
**** 19 Jan 1992
****
**** Description: The timer server for the ShellTimer system.
**** This daemon accepts requests from the client program, ShellTimer.
**** It maintains a dynamic list of timer sessions.
****
**** When the client requests that a timer session be started, the
**** daemon records the shell PID of the client and the current time
**** in an ST_Node data structure. Later client requests can query
**** the value of the timer, cancel the timer session, and stop the
**** the timer. The daemon can also be commanded to terminate.
**** Elapsed timer values are computed by the daemon and sent back to
**** client.
****
**** The AmigaDOS Break command can also be used to terminate the
**** daemon, by sending it a Control-C.
****
**** As written, this program requires AmigaDOS 2.04. It could
**** be modified to run under 1.3, but I don't have the inclination.
**** 2.0 features used include the AllocVec() call (love it!).
****
**** See ShellTimer.doc for more information.
****
**** The ShellTimer system (which includes the programs
**** ShellTimerDaemon and ShellTimer) is released into the Public
**** Domain by the author, John Lindwall. I ask that the archive
**** be kept intact with the docs and the source code. Bug reports
**** should be sent to me at johnl@crash.cts.com.
****
**** Note: The code is not commented ... sorry.
****
**** Overhauls:
***/
#include <exec/types.h>
#include <exec/ports.h>
#include <exec/memory.h>
#include <exec/libraries.h>
#include <dos/dos.h>
#include <devices/timer.h>
#include <proto/exec.h>
#include <proto/timer.h>
#include <proto/dos.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "ShellTimer.h"
#define APPNAME "ShellTimerDaemon"
#define ADOS2_VERSION 37
void CleanExit(char *, int);
void SetupTimerDevice(void);
void SetupMessagePort(void);
void ProcessMessages(void);
void StartTimer(struct ST_Message *msg);
void StopTimer(struct ST_Message *msg);
void QueryTimer(struct ST_Message *msg);
void CancelTimer(struct ST_Message *msg);
void SetupRequestList(void);
void DestroyRequestList(void);
BOOL InsertRequest(int requestID, struct timeval *startTime);
struct ST_Node *RemoveRequest(int requestID);
BOOL InitMsgEndDiffTime(struct ST_Message *msg, struct ST_Node *request,
struct timeval *currentTime);
void ToggleTimer(struct ST_Message *msg);
void Print(char *s);
struct ST_Node
{
struct Node node;
int requestID;
struct timeval startTime;
};
struct List requestList;
struct Library *TimerBase;
struct timerequest *TimerIO;
struct timeval *time;
struct MsgPort *publicPort;
UBYTE versionTag[] = "\0$VER: " APPNAME " 1.0 (03.02.92) by John Lindwall\n";
/* Disable SAS/C Control-C/D checking */
int CXBRK(void) { return(0); }
int chkabort(void) { return(0); }
void
main(int argc, char *argv[])
{
extern struct DOSLibrary *DOSBase;
if( DOSBase->dl_lib.lib_Version < ADOS2_VERSION )
{
CleanExit("AmigaDOS 2.0 required!\n", -20);
}
Forbid();
if( FindPort(ST_PORT) )
{
Permit();
CleanExit("Daemon already loaded!\n", -5);
}
Permit();
if( argc != 0 )
{
Print(&versionTag[7]);
}
#ifdef MWDEBUG
MWInit(NULL, 0, "CON:0/0/639/199/MemLib");
#endif
SetupTimerDevice();
SetupRequestList();
SetupMessagePort();
ProcessMessages();
CleanExit("Exiting.\n", 0);
}
void
SetupRequestList(void)
{
NewList(&requestList);
}
void
DestroyRequestList(void)
{
struct ST_Node *node;
while( (node = (struct ST_Node *) RemHead(&requestList)) != NULL )
{
FreeVec(node);
}
}
BOOL
InsertRequest(int requestID, struct timeval *startTime)
{
struct ST_Node *node;
if( (node = AllocVec(sizeof(struct ST_Node), MEMF_ANY)) == NULL )
{
return(FALSE);
}
node->requestID = requestID;
node->startTime.tv_secs = startTime->tv_secs;
node->startTime.tv_micro = startTime->tv_micro;
Enqueue(&requestList, (struct Node *)node);
return(TRUE);
}
struct ST_Node *
RemoveRequest(int requestID)
{
struct ST_Node *foundNode;
BOOL match;
static struct ST_Node copyOfFoundNode;
if( IsListEmpty(&requestList) )
{
return(NULL);
}
match = FALSE;
foundNode = (struct ST_Node *) requestList.lh_Head;
do
{
if( requestID == foundNode->requestID )
{
match = TRUE;
break;
}
foundNode = (struct ST_Node *) foundNode->node.ln_Succ;
}
while( ! match && foundNode->node.ln_Succ != NULL );
if( match )
{
Remove((struct Node *)foundNode);
CopyMem(foundNode, ©OfFoundNode, sizeof(struct ST_Node));
FreeVec(foundNode);
return(©OfFoundNode);
}
else
{
return(NULL);
}
}
void
ProcessMessages(void)
{
ULONG sigRecvd;
BOOL done = FALSE;
struct ST_Message *msg;
while( ! done )
{
sigRecvd = Wait(SIGBREAKF_CTRL_C | 1L << publicPort->mp_SigBit);
if( sigRecvd & SIGBREAKF_CTRL_C )
{
done = TRUE;
}
else
{
msg = (struct ST_Message *) GetMsg(publicPort);
#ifdef DEBUG
printf("STD: I got a message! : %ld\n", msg->code); fflush(stdout);
#endif
switch( msg->code )
{
case ST_START:
StartTimer(msg);
break;
case ST_STOP:
StopTimer(msg);
break;
case ST_CANCEL:
CancelTimer(msg);
break;
case ST_TOGGLE:
ToggleTimer(msg);
break;
case ST_QUERY:
QueryTimer(msg);
break;
case ST_QUIT:
done = TRUE;
break;
}
ReplyMsg((struct Message *)msg);
}
}
}
void
StartTimer(struct ST_Message *msg)
{
struct timeval currentTime;
GetSysTime(¤tTime);
RemoveRequest(msg->requestID);
if( InsertRequest(msg->requestID, ¤tTime) )
{
msg->startTime.tv_secs = currentTime.tv_secs;
msg->startTime.tv_micro = currentTime.tv_micro;
}
else
{
msg->code = ST_ERR;
}
}
void
StopTimer(struct ST_Message *msg)
{
struct ST_Node *request;
struct timeval currentTime;
GetSysTime(¤tTime);
if( (request = RemoveRequest(msg->requestID)) != NULL )
{
if( ! InitMsgEndDiffTime(msg, request, ¤tTime) )
{
msg->code = ST_TIMEWARP;
}
}
else
{
msg->code = ST_ERR_NO_PENDING;
}
}
void
QueryTimer(struct ST_Message *msg)
{
struct ST_Node *request;
struct timeval currentTime, trueStartTime;
GetSysTime(¤tTime);
if( (request = RemoveRequest(msg->requestID)) != NULL )
{
trueStartTime.tv_secs = request->startTime.tv_secs;
trueStartTime.tv_micro = request->startTime.tv_micro;
if( ! InitMsgEndDiffTime(msg, request, ¤tTime) )
{
msg->code = ST_TIMEWARP;
return;
}
}
else
{
msg->code = ST_ERR_NO_PENDING;
return;
}
if( ! InsertRequest(msg->requestID, &trueStartTime) )
{
msg->code = ST_ERR;
}
}
BOOL
InitMsgEndDiffTime(struct ST_Message *msg, struct ST_Node *request,
struct timeval *currentTime)
{
if( CmpTime(currentTime, &(request->startTime)) != -1 )
{
return(FALSE);
}
msg->endTime.tv_secs = currentTime->tv_secs;
msg->endTime.tv_micro = currentTime->tv_micro;
SubTime(currentTime, &(request->startTime));
msg->diffTime.tv_secs = currentTime->tv_secs;
msg->diffTime.tv_micro = currentTime->tv_micro;
return(TRUE);
}
void
CancelTimer(struct ST_Message *msg)
{
struct ST_Node *request;
if( (request = RemoveRequest(msg->requestID)) == NULL )
{
msg->code = ST_ERR;
}
}
void
ToggleTimer(struct ST_Message *msg)
{
struct ST_Node *request;
struct timeval currentTime;
GetSysTime(¤tTime);
if( (request = RemoveRequest(msg->requestID)) != NULL )
{
if( ! InitMsgEndDiffTime(msg, request, ¤tTime) )
{
msg->code = ST_TIMEWARP;
}
else
{
msg->code = ST_STOP;
}
}
else
{
if( InsertRequest(msg->requestID, ¤tTime) )
{
msg->startTime.tv_secs = currentTime.tv_secs;
msg->startTime.tv_micro = currentTime.tv_micro;
msg->code = ST_START;
}
else
{
msg->code = ST_ERR;
}
}
}
void
SetupMessagePort(void)
{
if( (publicPort = CreatePort(ST_PORT, 0)) == NULL )
{
CleanExit("Can't open public message port\n", -3);
}
}
void
SetupTimerDevice(void)
{
LONG error;
TimerIO = (struct timerequest *)
AllocVec(sizeof(struct timerequest), MEMF_PUBLIC | MEMF_CLEAR);
time = (struct timeval *)
AllocVec(sizeof(struct timeval), MEMF_PUBLIC | MEMF_CLEAR);
if( TimerIO == NULL || time == NULL )
{
CleanExit("Out of memory\n", -1);
}
if( error = OpenDevice(TIMERNAME, UNIT_MICROHZ,
(struct IORequest *) TimerIO, 0L) )
{
CleanExit("Can't open timer device\n", -2);
}
TimerBase = (struct Library *) TimerIO->tr_node.io_Device;
}
void
CleanExit(char *string, int returnCode)
{
struct ST_Message *msg;
if( string != NULL )
{
Print(APPNAME ": ");
Print(string);
}
DestroyRequestList();
if( publicPort )
{
while( msg = (struct ST_Message *) GetMsg(publicPort) )
{
msg->code = ST_ERR;
ReplyMsg((struct Message *)msg);
}
DeletePort(publicPort);
}
if( TimerBase )
{
CloseDevice((struct IORequest *) TimerIO);
}
if( TimerIO )
{
FreeVec(TimerIO);
}
if( time )
{
FreeVec(time);
}
#ifdef MWDEBUG
MWTerm();
#endif
exit(returnCode);
}
void
Print(char *string)
{
Write(Output(), string, strlen(string));
}